/****************************************************************************
 * (c) 2001 StreamBox Inc.  http://www.streambox.com/ 
 *
 * Division: Moscow Research Division
 * Project:  Tidy Scaling (video compression project)
 *
 * Contents: Filter-based scaling functions. Only ^2 scaling factor allowed.
 *           File contains 8-item fast filter implemntation.
 *
 * History:  29-Aug-2001 - Created by Dmitriy Vatolin, modified ScaleLineUpX2Filter8_2MMX by Smirnov K
 *           06-Sep-2001 - new filter coefficients, MMX version, add ScaleInitFilter8_2()
 *           07-Sep-2001 - rewrited ScaleLineUpX2Filter8_2 with less memory usage
 *           08-Sep-2001 - inline assembler in ScaleLineUpX2Filter8_2MMX
 *           10-Sep-2001 - inline assembler in ScaleLineUpX2Filter8_2MMX
 ****************************************************************************/
/**
 * \file scale_msk_f8_mmx.c
 *  File contains 8-item fast filter implemntation. 
 *  Filter coeficients {-4 -9 19 58 58 19 -9 -4}
 *  void ScaleChannelUpX2Filter8_2VerticalMMX()
 *  void ScaleChannelUpX2Filter8_2HorisontalMMX()
 *  void ScaleChannelDownX2Filter8_2VerticalMMX()
 *  void ScaleChannelDownX2Filter8_2HorisontalMMX()
 */ 


#include "../Lib/Scale_msk.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#ifdef _MMX_

#include <mmintrin.h>

/*============================= ScaleChannelUpX2Filter8_2VerticalMMX ==============================*/
/**
 * Scale UP Vertical Dimension of 2D channel using MMX. 
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height  
 * \retval - none
 */
void ScaleChannelUpX2Filter8_2VerticalMMX(BYTE* in, BYTE* out, int w, int h)
{
	int w3 = w&3?((w>>2)+1):w>>2, h_3 = h -3;
    int i,c,c2,c3,c4;
	BYTE *inb = in, *outb = out;

    const __m64 mmx_58 = _mm_set1_pi16(58);
    const __m64 mmx_19 = _mm_set1_pi16(19);
    const __m64 mmx__9 = _mm_set1_pi16(-9);
    const __m64 mmx__4 = _mm_set1_pi16(-4);
    const __m64 mmx_32 = _mm_set1_pi16(32);
	
		for (i= 0; i<w; i++)
		{
			c =in[i];
			c2=in[i+w];
			c3=in[i+2*w];
			out[i]= CLIP_F( (58*c + 19*c2 - 4*c3 + 36)/73 );
			out[i+w]= CLIP_F( (19*c + 58*c2 - 9*c3 + 34)/68 );
		}

	
    __asm {

			pushad
			mov			edx, dword ptr [w]			//increment for next out[]
			mov			eax, edx
			neg			eax							// [-w]
			mov			ebx, dword ptr[h_3]

            mov         esi, dword ptr [inb]
            mov         edi, dword ptr [outb]
			lea			esi, [esi+edx]
			lea			edi, [edi+edx*2]
            mov         dword ptr [inb], esi
            mov         dword ptr [outb], edi
loop_h:
			mov			ecx, dword ptr [w3]			// counter
										
loop_v4:
		//------------------------------------------------------
			pxor		mm4, mm4
            movd		mm0, dword ptr [esi+eax]	//in[-w]
			punpcklbw	mm0, mm4// 
            movd		mm1, dword ptr [esi]		//in[0]
			punpcklbw	mm1, mm4// 
            movd		mm2, dword ptr [esi+edx]	//[w]
			punpcklbw	mm2, mm4// 
            movd		mm3, dword ptr [esi+edx*2]	//[w*2]
			punpcklbw	mm3, mm4//

			movq		mm4, mm0
			movq		mm5, mm1
			movq		mm6, mm2
			movq		mm7, mm3					// save old
			pmullw		mm0, mmword ptr[mmx__9]		//*-9
			pmullw		mm1, mmword ptr[mmx_58]		//*58
			pmullw		mm2, mmword ptr[mmx_19]		//*19
			pmullw		mm3, mmword ptr[mmx__4]		//*-4
			paddsw		mm0, mm1
			paddsw		mm0, mm2
			paddsw		mm0, mm3					//result1
			paddsw		mm0, mmword ptr[mmx_32]
			psraw		mm0, 6h
			packuswb	mm0, mm0					//4 bytes

			pmullw		mm4, mmword ptr[mmx__4]
			pmullw		mm5, mmword ptr[mmx_19]
			pmullw		mm6, mmword ptr[mmx_58]
			pmullw		mm7, mmword ptr[mmx__9]
			paddsw		mm4, mm5
			paddsw		mm4, mm6
			paddsw		mm4, mm7					//result2
			paddsw		mm4, mmword ptr[mmx_32]
			psraw		mm4, 6h
			packuswb	mm4, mm4
			movd		dword ptr [edi], mm0		//save in out
			movd		dword ptr [edi+edx], mm4

			add			edi, 4h
			add			esi, 4h

			dec ecx
			jnz loop_v4
            mov         esi, dword ptr [inb]
            mov         edi, dword ptr [outb]
			lea			esi, [esi+edx]
			lea			edi, [edi+edx*2]
            mov         dword ptr [inb], esi
            mov         dword ptr [outb], edi
			dec	ebx
			jnz loop_h
			popad
			emms
		}
	
		outb = out+(h*2-3)*w;			// pointer to out
		inb = in+(h-3)*w;			// pointer to out
		for (i=0; i<w; i++)
		{
			c2= inb[i+2*w]; 
			c3= inb[i+w  ];
			c4= inb[i    ];
			outb[i+2*w]=	CLIP_F( ((58+19)*c2 - 4*c3 + 36)/73 ); 
			outb[i+w  ]=	CLIP_F( ((19+58)*c2 - 9*c3 + 34)/68 );
			outb[i    ]=	CLIP_F( ((-9+58)*c2 + 19*c3 -4*c4 + 32)>>6 );
			outb[i-w  ]=	CLIP_F( ((-4+19)*c2 + 58*c3 -9*c4 + 32)>>6 );
		}
}

/*============================= ScaleChannelUpX2Filter8_2HorisontalMMX ==============================*/
/**
 * Scale UP Horisontal Dimension of 2D channel using MMX. 
 * 
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */
void ScaleChannelUpX2Filter8_2HorisontalMMX( BYTE *src, BYTE *dst, int w , int h)
{
	int wx2 = w*2;
    int i,d,c,c2,c3,c4,q_in, q_out, loop_counter;

    const __m64 mmx_f1 = _mm_set_pi16(-9, 58, 19, -4);	//settings for MMX
    const __m64 mmx_f2 = _mm_set_pi16(-4, 19, 58, -9);
    const __m64 mmx_3232 = _mm_set_pi16(32, 32, 32, 32);

	__m64 mmx_reg;

	  
	/*---------------------------- Horizontal pass  ---------------------------------*/


	i = 0;					// cycle counter (for i=0; i<h; i++)
    do 
    {

        q_in=i*w;
		q_out=i*wx2;	// calculating address
        
		c =src[q_in  ];
        c2=src[q_in+1];
        c3=src[q_in+2];
        dst[q_out]  = CLIP_F((58*c + 19*c2 - 4*c3 + 36)/73);
        dst[q_out+1]= CLIP_F((19*c + 58*c2 - 9*c3 + 34)/68);

		mmx_reg = _mm_set_pi16( 0, c, c2, c3);//, src[3]);

        d=(i+1)*w-1;		// save src memory for right bound
        c2= src[d  ]; 
        c3= src[d-1];
        c4= src[d-2];

        q_out+=2;
        
		loop_counter = (w>>1)-1; 




    __asm {
			pushad
            movq        mm7, mmword ptr [mmx_reg]
            mov         ecx, dword ptr [dst]
			mov			eax, dword ptr [q_out]
			lea			edi, [ecx+eax]		//EDI-dest
            mov         ecx, dword ptr [src]
			mov			eax, dword ptr [q_in]
			lea			esi, [ecx+eax+3]	//ESI-source

			mov			ecx, dword ptr[loop_counter]
			xor			eax, eax
			pxor		mm6,mm6


			mov         al, byte ptr[esi]//pre-read
loop_start:
			//---------------------------------------------------------- first half

            psllq       mm7, 10h
            movd        mm0, eax			//mm0(low) = ax
			mov			al, byte ptr [esi+1] // pre-read
            por         mm7, mm0			// mm3 = (c, c2, c3, src[3])


            movq        mm2, mm7
            pmaddwd     mm2, mmword ptr [mmx_f1]

            movq        mm0, mm7
            pmaddwd     mm0, mmword ptr [mmx_f2]			//mm0 = halfsumm2

			// add dwords horizontal
			movq		mm1,mm2
			punpckldq	mm2,mm0
			punpckhdq	mm1,mm0
			paddd		mm2,mm1

			//---------------------------------------------------------- second half
            psllq       mm7, 10h
            movd        mm3, eax	

			add         esi, 2				//increment for pointers

            por         mm7, mm3
			mov         al, byte ptr[esi] // pre-read
            movq        mm1, mm7
            pmaddwd     mm1, mmword ptr [mmx_f1]

            movq        mm4, mm7
            pmaddwd     mm4, mmword ptr [mmx_f2]

			// add dwords horizontal
			movq		mm3,mm1
			punpckldq	mm3,mm4
			punpckhdq	mm1,mm4
			paddd		mm3,mm1

			packssdw	mm2, mm3
			paddsw		mm2, mmword ptr [mmx_3232] 
			psraw		mm2, 6h

			packuswb	mm2, mm6			//
            movd        word ptr [edi], mm2	// save src dst[q]
            add         edi, 4				//

		//------------------------ end of inner loop ------------------------- //
			dec ecx
			jnz		loop_start
			popad
        }

	
        q_out=(i+1)*wx2-1;
        dst[q_out  ]= CLIP_F(((58+19)*c2 - 4*c3 + 36)/73); 
        dst[q_out-1]= CLIP_F(((19+58)*c2 - 9*c3 + 34)/68);
        dst[q_out-2]= CLIP_F(((-9+58)*c2 + 19*c3 -4*c4 + 32)>>6);
        dst[q_out-3]= CLIP_F(((-4+19)*c2 + 58*c3 -9*c4 + 32)>>6);
		i++;
	
	} while (i<h);// end of horisontal pass
	__asm 	emms;

}




/*============================= InitmmxTable ==============================*/
/**
 * Create mmx_table[] for ScaleChannelUpX2Filter8_2HorisontalMMX2. 
 * 
 *
 * \has no param 
 * \retval - none
 */
__m64 mmx_table[512];

void InitmmxTable()
{
	int i;
	__m64 f0 = _mm_set_pi16(-4, 19, 58, -9);
	__m64 f1 = _mm_set_pi16(-9, 58, 19, -4);

	for (i = 0; i<256; i++)
	{
		mmx_table[i] = _mm_mullo_pi16(_mm_set1_pi16(i), f1);
		mmx_table[i+256] = _mm_mullo_pi16(_mm_set1_pi16(i), f0);
	}
	_mm_empty();
}


/*============================= ScaleChannelUpX2Filter8_2HorisontalMMX2 ==============================*/
/**
 * Scale UP Horisontal Dimension of 2D channel using MMX. 
 * 
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */

void ScaleChannelUpX2Filter8_2HorisontalMMX2( BYTE *src, BYTE *dst, int w , int h)
{
	int wx2 = w*2;
    int i,d,c,c2,c3,c4,q_in, q_out, loop_counter;
	__m64 *t = mmx_table;

    const __m64 mmx_3232 = _mm_set_pi16((short)32, (short)32, (short)32, (short)32);
    const __m64 mmx_ffff = _mm_set_pi16((short)0, (short)0, (short)0xffff, (short)0xffff);

	  
	/*---------------------------- Horizontal pass  ---------------------------------*/

		loop_counter = (w>>1)-1; 

	i = 0;					// cycle counter (for i=0; i<h; i++)
    do 
    {

        q_in=i*w;
		q_out=i*wx2;	// calculating address
        
		c =src[q_in  ];
        c2=src[q_in+1];
        c3=src[q_in+2];
        dst[q_out]  = CLIP_F((58*c + 19*c2 - 4*c3 + 36)/73);
        dst[q_out+1]= CLIP_F((19*c + 58*c2 - 9*c3 + 34)/68);

        d=(i+1)*w-1;		// save src memory for right bound
        c2= src[d  ]; 
        c3= src[d-1];
        c4= src[d-2];



    __asm {
			pushad
            mov         ecx, dword ptr [dst]
			mov			eax, dword ptr [q_out]
			lea			edi, [ecx+eax+2]		//EDI-dest
            mov         ecx, dword ptr [src]
			mov			eax, dword ptr [q_in]
			lea			esi, [ecx+eax]	//ESI-source
			mov			ebx, [t]

			movd		mm7, mmword ptr[mmx_ffff]
			movd		mm6, mmword ptr[mmx_3232]

			mov			ecx, dword ptr[loop_counter]

			xor			eax, eax

			pxor		mm1,mm1
			pxor		mm0,mm0

			mov         al, byte ptr[esi]//pre-read

			movq		mm2, mmword ptr [ebx+eax*8]
			movq		mm3, mmword ptr [ebx+eax*8+2048]

			mov         al, byte ptr[esi+1]//pre-read

			psrlq		mm2, 10h
			psrlq		mm3, 10h
			paddw		mm2, mmword ptr [ebx+eax*8]
			paddw		mm3, mmword ptr [ebx+eax*8+2048]

			mov         al, byte ptr[esi+2]//pre-read

			psrlq		mm2, 10h
			psrlq		mm3, 10h
			paddw		mm2, mmword ptr [ebx+eax*8]
			paddw		mm3, mmword ptr [ebx+eax*8+2048]

			add			esi, 3

loop_start:
			//---------------------------------------------------------- first half
			mov         al, byte ptr[esi]//pre-read
			psrlq		mm2, 10h
			psrlq		mm3, 10h
			paddw		mm2, mmword ptr [ebx+eax*8]
			paddw		mm3, mmword ptr [ebx+eax*8+2048]

			movq		mm4, mm2
			punpcklwd	mm4, mm3

			movq		mm5, mm4

			mov         al, byte ptr[esi+1]//pre-read
			psrlq		mm2, 10h
			psrlq		mm3, 10h
			paddw		mm2, mmword ptr [ebx+eax*8]
			paddw		mm3, mmword ptr [ebx+eax*8+2048]

			movq		mm4, mm2
			punpcklwd	mm4, mm3
			pand		mm5, mm7			//00000000ffffffff
			psllq		mm4, 20h
			por			mm5, mm4

			add			esi, 2

			paddsw		mm5, mm6			//32323232 
			psraw		mm5, 6h

			packuswb	mm5, mm0			//
            movd        dword ptr [edi], mm5// save src dst[q]
			add			edi, 4

			dec ecx
			jnz		loop_start
			popad
        }

	
        q_out=(i+1)*wx2-1;
        dst[q_out  ]= CLIP_F(((58+19)*c2 - 4*c3 + 36)/73); 
        dst[q_out-1]= CLIP_F(((19+58)*c2 - 9*c3 + 34)/68);
        dst[q_out-2]= CLIP_F(((-9+58)*c2 + 19*c3 -4*c4 + 32)>>6);
        dst[q_out-3]= CLIP_F(((-4+19)*c2 + 58*c3 -9*c4 + 32)>>6);
		i++;
	
	} while (i<h);// end of horisontal pass
	__asm 	emms;

}







/*============================= ScaleChannelDownX2Filter8_2Vertical ==============================*/
/**
 * Scale DOWN one line with 8-items filter. 
 *
 * \param sfd         [IN]  - pointer to the filter object 
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param w           [IN]  - in-buffer length
 * \param l           [IN]  - in-buffer length
 * \retval - none
 */
void ScaleChannelDownX2Filter8_2VerticalMMX(BYTE *in, BYTE *out, int w, int h)
{
	int i;
	int w_in = w, h_in = h, h_out = h_in>>1, w_out = w_in, h_end = h_out - 3;
	int w_in8 = (w_in>>3)+1;
	BYTE * pIn, *pOut;

    const __m64 mmx__4   = _mm_set1_pi16(-4);	
    const __m64 mmx__9   = _mm_set1_pi16(-9);
    const __m64 mmx_19   = _mm_set1_pi16(19);
    const __m64 mmx_58   = _mm_set1_pi16(58);
    const __m64 mmx_6464 = _mm_set1_pi16(64);

	pIn = in;
	pOut = out;

	for(i = 0; i<w_in; i++)
	{
		pOut[i]=		CLIP_F(( 58* pIn[i       ] 
								+19* pIn[i+w_in  ] 
								- 9* pIn[i+w_in*2] 
								- 4* pIn[i+w_in*3] + 32)>>6 );
		
		pOut[i+w_in]=	CLIP_F(( 58*(pIn[i+w_in*2] + pIn[i+w_in  ])
								+19*(pIn[i+w_in*3] + pIn[i       ])
								- 9* pIn[i+w_in*4] 
								- 4* pIn[i+w_in*5] + 70)/141 );
	}
               
	pOut = out +w_out*2;

/*	for(j = 0; j<h_end; j++)
	{
		for(i=0; i<w_in; i++)
		{
		    pOut[i] = CLIP_F( ( 58*(pIn[i+w_in*4] + pIn[i+w_in*3]) 
							   +19*(pIn[i+w_in*5] + pIn[i+w_in*2])
							   - 9*(pIn[i+w_in*6] + pIn[i+w_in  ]) 
							   - 4*(pIn[i+w_in*7] + pIn[i       ]) +64)>>7 );
	    }
		pIn  += w_in*2;
		pOut += w_out;
	}
*/


	__asm{
		pushad
		mov		esi, dword ptr [pIn]
		mov		edi, dword ptr [pOut]
		mov		edx, dword ptr [w_in]
		mov		eax, edx
		lea		ecx, [edx*2+eax]		//w_in*3
		neg		eax						//-w_in
		pxor		mm7, mm7

loop_h:
		mov		ebx, dword ptr [w_in8]
loop_w:
		movq	mm0, mmword ptr [esi]		//0 row
		movq	mm1, mm0
		punpcklbw	mm0, mm7// 
		punpckhbw	mm1, mm7// 

		movq	mm2, mmword ptr [esi+edx]		//1row
		movq	mm3, mm2
		punpcklbw	mm2, mm7// 
		punpckhbw	mm3, mm7// 

		lea		esi, [esi+edx*4]

		movq	mm4, mmword ptr [esi+ecx]		//7row
		movq	mm5, mm4
		punpcklbw	mm4, mm7// 
		punpckhbw	mm5, mm7// 

		movq		mm6, mmword ptr [mmx__4]
		paddw		mm0, mm4
		paddw		mm1, mm5
		pmullw		mm0, mm6
		pmullw		mm1, mm6
	
		movq	mm4, mmword ptr [esi+edx*2]		//6row
		movq	mm5, mm4
		punpcklbw	mm4, mm7// 
		punpckhbw	mm5, mm7// 

		movq		mm6, mmword ptr [mmx__9]
		paddw		mm2, mm4
		paddw		mm3, mm5
		pmullw		mm2, mm6
		pmullw		mm3, mm6
		paddw		mm0, mm2//acc
		paddw		mm1, mm3//acc

		movq	mm2, mmword ptr [esi+eax*2]		//2row
		movq	mm3, mm2
		punpcklbw	mm2, mm7// 
		punpckhbw	mm3, mm7// 

		movq	mm4, mmword ptr [esi+edx]		//5row
		movq	mm5, mm4
		punpcklbw	mm4, mm7// 
		punpckhbw	mm5, mm7// 

		movq		mm6, mmword ptr [mmx_19]
		paddw		mm2, mm4
		paddw		mm3, mm5
		pmullw		mm2, mm6
		pmullw		mm3, mm6
		paddw		mm0, mm2//acc
		paddw		mm1, mm3//acc
	
		movq	mm2, mmword ptr [esi+eax]		//3row
		movq	mm3, mm2
		punpcklbw	mm2, mm7// 
		punpckhbw	mm3, mm7// 

		movq	mm4, mmword ptr [esi]			//4row
		movq	mm5, mm4
		punpcklbw	mm4, mm7// 
		punpckhbw	mm5, mm7// 

		movq		mm6, mmword ptr [mmx_58]
		paddw		mm2, mm4
		paddw		mm3, mm5
		pmullw		mm2, mm6
		pmullw		mm3, mm6
		paddsw		mm0, mm2//acc
		paddsw		mm1, mm3//acc, end add

		movq		mm6, mmword ptr [mmx_6464]
		paddsw		mm0, mm6 
		paddsw		mm1, mm6 
		psraw		mm0, 7h
		psraw		mm1, 7h
		packuswb	mm0, mm1			//
        movq        dword ptr [edi], mm0	// save in out[q]

		lea			esi, [esi+eax*4+8]// restore & next pos in 0 row
        add         edi, 8h				//

		dec			ebx
		jnz			loop_w

		mov		esi, dword ptr [pIn]
		mov		edi, dword ptr [pOut]
		lea		esi, [esi+edx*2]
		lea		edi, [edi+edx]
		mov		dword ptr [pIn], esi
		mov		dword ptr [pOut], edi


		mov			ebx, dword ptr [h_end]
		dec			ebx
		mov			dword ptr [h_end], ebx
		jnz			loop_h
		popad
		emms
	}

	
	
	for(i = 0; i<w_in; i++)
	{
	    pOut[i]=	  CLIP_F( ( 58*(pIn[i+w_in*3] + pIn[i+w_in*4]) 
							   +19*(pIn[i+w_in*2] + pIn[i+w_in*5]) 
							   - 9* pIn[i+w_in  ] 
							   - 4* pIn[i       ] + 70)/141 );
	}
}                                                                            

/*============================= ScaleChannelDownX2Filter8_2Horisontal ==============================*/
/**
 * Scale DOWN one line with 8-items filter. 
 *
 * \param sfd         [IN]  - pointer to the filter object 
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param l           [IN]  - in-buffer length
 * \retval - none
 */
void ScaleChannelDownX2Filter8_2HorisontalMMX(BYTE *in, BYTE *out, int w, int h)
{
	int j;
	int w_in = w, h_in = h, h_out = h_in, w_out = w_in>>1, w_end = w_out - 3;
	int w_end4 = (w_end>>2)+1;
	BYTE * pIn, *pOut;

    const __m64 mmx_f1   = _mm_setr_pi16(-4, -9, 19, 58);	
    const __m64 mmx_f2   = _mm_set_pi16(-4, -9, 19, 58);	
    const __m64 mmx_6464   = _mm_set1_pi16(64);	

	for (j = 0; j<h_out; j++)
	{
		pIn = in + j*w_in;
		pOut = out + j*w_out;

		pOut[0]=		CLIP_F(( 58* pIn[0] 
								+19* pIn[1] 
								- 9* pIn[2] 
								- 4* pIn[3] + 32)>>6 );
		
		pOut[1]=		CLIP_F(( 58*(pIn[2] + pIn[1])
								+19*(pIn[3] + pIn[0])
								- 9* pIn[4] 
								- 4* pIn[5] + 70)/141 );
	                                                               
	pOut += 2;

/*
		for(i=0; i<w_end;i++)
		{
	        pOut[i]=	CLIP_F(( 58*(pIn[3] + pIn[4]) 
								+19*(pIn[2] + pIn[5])
							    - 9*(pIn[1] + pIn[6]) 
						        - 4*(pIn[0] + pIn[7]) +64)>>7 );
			pIn+=2;
		}

*/
	__asm{
		pushad
		mov		esi, dword ptr [pIn]
		mov		edi, dword ptr [pOut]

		pxor		mm7, mm7
		movq		mm4, mmword ptr [mmx_f1]
		movq		mm5, mmword ptr [mmx_f2]
		xor			eax, eax


		mov		ecx, dword ptr [w_end4]
		movq	mm0, mmword ptr [esi]
		add		esi,8

loop_w:
//0		
		movq	mm3, mmword ptr [esi]
		movq	mm1, mm0
		movq	mm2, mm0
		punpcklbw	mm1, mm7// 
		punpckhbw	mm2, mm7// 
		pmaddwd		mm1, mm4
		pmaddwd		mm2, mm5
		paddw		mm1, mm2//2 int
		movq		mm2, mm1//2 int
		psrlq		mm2, 20h//>>32
		paddsw		mm1, mm2//+shorts=1 saturated shorts
		pextrw		eax, mm1, 0h
		pinsrw		mm6, eax, 0h
//1
		psrlq		mm0, 10h
		pextrw		eax, mm3, 0h
		pinsrw		mm0, eax, 3h

		movq	mm1, mm0
		movq	mm2, mm0
		punpcklbw	mm1, mm7// 
		punpckhbw	mm2, mm7// 
		pmaddwd		mm1, mm4
		pmaddwd		mm2, mm5
		paddw		mm1, mm2//2 int
		movq		mm2, mm1//2 int
		psrlq		mm2, 20h//>>32
		paddsw		mm1, mm2//+shorts=1 saturated shorts
		pextrw		eax, mm1, 0h
		pinsrw		mm6, eax, 1h
//2
		psrlq		mm0, 10h
		pextrw		eax, mm3, 1h
		pinsrw		mm0, eax, 3h

		
		movq	mm1, mm0
		movq	mm2, mm0
		punpcklbw	mm1, mm7// 
		punpckhbw	mm2, mm7// 
		pmaddwd		mm1, mm4
		pmaddwd		mm2, mm5
		paddw		mm1, mm2//2 int
		movq		mm2, mm1//2 int
		psrlq		mm2, 20h//>>32
		paddsw		mm1, mm2//+shorts=1 saturated shorts
		pextrw		eax, mm1, 0h
		pinsrw		mm6, eax, 2h
//3
		psrlq		mm0, 10h
		pextrw		eax, mm3, 2h
		pinsrw		mm0, eax, 3h
		
		movq	mm1, mm0
		movq	mm2, mm0
		punpcklbw	mm1, mm7// 
		punpckhbw	mm2, mm7// 
		pmaddwd		mm1, mm4
		pmaddwd		mm2, mm5
		paddw		mm1, mm2//2 int
		movq		mm2, mm1//2 int
		psrlq		mm2, 20h//>>32
		paddsw		mm1, mm2//+shorts=1 saturated shorts
		pextrw		eax, mm1, 0h
		pinsrw		mm6, eax, 3h

		paddsw		mm6, mmword ptr [mmx_6464]
		psraw		mm6, 7h
		packuswb	mm6, mm7			//
		
		movq		mm0, mm3
		add			esi, 8h
        movd        dword ptr [edi], mm6	// save in out[q]
		add			edi, 4h

		dec			ecx
		jnz			loop_w
		popad

	}
		

	pOut += w_end;
	pIn += w_end*2;
	
	    pOut[0]=		CLIP_F(( 58*(pIn[3] + pIn[4]) 
							    +19*(pIn[2] + pIn[5]) 
							    - 9* pIn[1] 
							    - 4* pIn[0] + 70)/141 );
	}
	__asm emms
}                                                                            


#endif /*MMX*/
/************************  end of file **************************************/
